#  -*-  coding: utf-8  -*-

import time
import random
import urllib2
import hashlib
import xml.etree.cElementTree as ET

import Tkinter as tk
import ScrolledText as st


settings = {
    # `ToUserName` & `FromUserName` will be placed in the XML data posted to
    # the given URL.
    "ToUserName": "gh_bea8cf2a04fd",
    # 用户ids数组, 微信号"微校园"上的..
    "FromUserName": [   "oMDSlt8MrTwAzo9DSBgM060xT7HM", 
                        "oMDSlt5kvDJfw9sqTbrOrXQbBa4U", 
                        "oMDSlt8Kc38w-2-RKFKVBdslYLrM", 
                        "oMDSlt7-JbSXGf_xzIvmCx7UOUak", 
                        "oMDSlt7y4ed89HmmyNPhV4eF8N2A", 
                        "oMDSltws8PfF08kHRX5Rn6XfA9aM", 
                        "oMDSltw9cMMCvi4_kJN9diwtwBaY", 
                        "oMDSltzXQmQciJSN53NDHEDWW0Nk", 
                        "oMDSlt7Mq2RQp98rAlfWNl3zN9DE", 
                        "oMDSlt2V0zLQ5pfEZIJhkvFXx83w", 
                        "oMDSlt37q1AdVruCDVXT51OmMmxs", 
                        "oMDSlt2Yyd8LLjssCiy1vtXUFpSA", 
                        "oMDSlt6-x9DUnPQgUhPxVctS-uDc", 
                        "oMDSltyuCG_ynpdXQDOCL6TcyQy4", 
                        "oMDSltyEJtncHV2y0DEnnSMfinxY", 
                        "oMDSltwyvvTnHuWNzK6UFk0KbEsg", 
                        "oMDSlt7Bgfa-L7RD6SbMYvI39Hrk", 
                        "oMDSlt-yu_mq8mfM5EjIz2hofqEU", 
                        "oMDSlt08SitiPF9LEYO0F5GeZbEA", 
                        "oMDSlt3C4f1BSDZfZzmzjvYS0UOE", 
                        "oMDSlt8Ig8vjZkXhc-oWJL9CPpG8", 
                        "oMDSlt3uCLvXZMc54nvky2UkDL3k", 
                        "oMDSlt_0NJG-PesBQNO8uSN6qbz0", 
                        "oMDSlt3Hr8y0A1jf2lCGInZXF_lc", 
                        "oMDSlt1qnYICEeyBG_mTcRXNlYCQ", 
                        "oMDSlt8sw36tiQNW6hO0a8lzCdzs", 
                        "oMDSlt38dOOa6tMVU9jnmm-MfNJ4", 
                        "oMDSlt8lmnH3RQh1hE74xkfKEe38", 
                        "oMDSltxUC6xDAsP3RVUawLMWPyGs", 
                        "oMDSlt_iUfm6_yMLa4zCqvuFbJDg", 
                        "oMDSltztg-2HRj5ndftpgy-ezBdk", 
                        "oMDSlt-ivorv-swv5MOsrB8HFSdk", 
                        "oMDSlt5WBTAimRPXGrtdWMSj3paU", 
                        "oMDSlt1_j3B_IH7DH2QTiyBbg3_4", 
                        "oMDSlt1OkpT0NH7lEUl6Jk5l8ioA", 
                        "oMDSlt_LraoY4rNr-qLc9JYru47w", 
                        "oMDSltzJqYCPD5yOBAz3k9T8NjVU" ],

    # URL of your Wexin handler.
    "url": "http://localhost:3000/interface",

    # These will be displayed in GUI.
    "mp_display_name": "APP",
    "me_display_name": "ME",

    # The token you submitted to Weixin MP. Used to generate signature.
    "token": "pas123xxzcniii123909"
}


TPL_TEXT = '''
<xml>
    <ToUserName><![CDATA[%(to)s]]></ToUserName>
    <FromUserName><![CDATA[%(from)s]]></FromUserName>
    <CreateTime>%(time)d</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[%(content)s]]></Content>
    <MsgId>$(id)s</MsgId>
</xml>
'''

TPL_EVENT = '''
<xml>
    <ToUserName><![CDATA[%(to)s]]></ToUserName>
    <FromUserName><![CDATA[%(from)s]]></FromUserName>
    <CreateTime>%(time)d</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[%(event)s]]></Event>
    <EventKey><![CDATA[%(key)s]]></EventKey>
</xml>'''


def post(url, data):
    request = urllib2.Request(url, data)
    request.add_header("Content-Type", "text/xml")
    response = urllib2.urlopen(request)
    return response.read()


def send():
    count = 0
    send_t = int(send_times.get())
    for _ in range(send_t):
        for open_id in settings["FromUserName"]:
            s = e.get().encode('utf-8') + str(random.random())[-10:]    # Fix Chinese input.
            if s:
                t.insert(tk.END, open_id +"\n", "send_name")
                t.insert(tk.END, s+"\n", "send_content")

                msg = {
                    "to": settings["ToUserName"],
                    "from": open_id,
                    "time": time.time(),
                    "content": s,
                    "id": str(random.random())[-10:]
                }

                qs = "?signature=%s&timestamp=%s&nonce=%s" % \
                    mix(int(msg["time"]), msg["id"])
                receive(msg["time"], post(settings["url"]+qs, TPL_TEXT % msg))
                count = count + 1
    t.insert(tk.END, "发送次数：" + str(count) +"\n", "times")

def receive(start, response):
    if time.time() - start > 4.95:
        return

    et = ET.fromstring(response)
    print "Received:\n%s\n" % response

    c = unicode(et.find("Content").text)

    t.insert(tk.END, settings["mp_display_name"]+"\n", "receive_name")
    t.insert(tk.END, c+"\n", "receive_content")


def mix(time, salt):
    timestamp = str(time)
    
    # I don't know how Weixin generate nonce, so I turn to random.
    nonce = str(time + int(salt[-6:]))

    l = [timestamp, nonce, settings["token"]]
    l.sort()
    signature = hashlib.sha1("".join(l)).hexdigest()

    return (signature, timestamp, nonce)


def follow():
    for open_id in settings["FromUserName"]:
        msg = {
            "to": settings["ToUserName"],
            "from": open_id,
            "time": time.time(),
            "event": "subscribe",
            "key": ""       # `EventKey` in `subscribe` event is empty.
        }
        qs = "?signature=%s&timestamp=%s&nonce=%s" % \
            mix(int(msg["time"]), str(random.random())[-10:])
        receive(msg["time"], post(settings["url"]+qs, TPL_EVENT % msg))


top = tk.Tk()
top.title("微信模拟器 - fork by Special")

t = st.ScrolledText(top, width=40)
t.pack()

t.tag_add("send_name", "1.0", "1.end")
t.tag_config("send_name", font=("Arial", "10", "bold"),
            justify=tk.RIGHT, rmargin=6)
t.tag_add("send_content", "2.0", "2.end")
t.tag_config("send_content", spacing3=10, justify=tk.RIGHT, rmargin=6)

t.tag_add("receive_name", "1.0", "1.end")
t.tag_config("receive_name", font=("Arial", "10", "bold"), lmargin1=2)
t.tag_add("receive_content", "2.0", "2.end")
t.tag_config("receive_content", spacing3=10, lmargin1=2)

label = tk.Label(top, text = '每个账号发送次数')
label.pack()

send_times = tk.Entry(top)
send_times.pack()

e = tk.Entry(top)
e.pack(side=tk.LEFT)

b = tk.Button(top, text="发送", command=send)
b.pack(side=tk.LEFT)

a = tk.Button(top, text="关注公众帐号", command=follow)
a.pack(side=tk.RIGHT)

if __name__ == "__main__":
    top.mainloop()
